home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / Hier Menu Demo ƒ / Hier Menu Demo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-14  |  14.2 KB  |  628 lines  |  [TEXT/KAHL]

  1. /*
  2. *Program name: Hier Menu Demo
  3. *
  4. *Author:  Ted C. Johnson, Sun, Aug 14 1988.
  5. *
  6. *Compilation instructions:  use Lightspeed C, v.2.15.  This program DOES
  7. *                            use a resource file.  I developed this program
  8. *                            on a Mac SE HD20 running System/Finder 4.1/5.5.
  9. *
  10. *Summary:  This program demonstrates how to use hierarchical menus.  It 
  11. *           also demonstrates how to handle DA's, how to make your own
  12. *           "About…" box (with an icon), and how to use dialog boxes.
  13. *
  14. *           The use of this source code is free, provided it is for 
  15. *           non-profit purposes.  I hope it can save someone some time!
  16. *
  17. *           However the name "T Bear Software" and the T Bear icon are 
  18. *           both CopyRight © 1988 by Ted C. Johnson, and may NOT be used 
  19. *           without my express written permission.
  20. */
  21.  
  22.  
  23.  
  24. #include <QuickDraw.h>
  25. #include <WindowMgr.h>
  26. #include <EventMgr.h>
  27. #include <MenuMgr.h>
  28. #include <DialogMgr.h>
  29. #include <FontMgr.h>
  30. #include <DeskMgr.h>
  31. #include <MacTypes.h>
  32. #include <TextEdit.h>
  33.  
  34.  
  35.  
  36. #define int32        long
  37. #define    int16        int
  38. #define int8        char
  39.  
  40. #define NIL            0L
  41.  
  42.  
  43.  
  44. /*Define the ID for our DLOG and DITL resource.*/
  45.  
  46. #define DIALOG_MESSAGE 777
  47.  
  48.  
  49. /*
  50. *Define our menu IDs.  My unusual spacing is meant to give you a
  51. *picture of how the sub-menus relate to their parent menu.
  52. */
  53.  
  54. #define APPLE_ID        10
  55.  
  56. #define    FILE_ID            20
  57.  
  58. #define FONT_N_DA_ID    30
  59. #define        FONT_ID            31 /*Fonts.*/
  60. #define        DA_ID            32 /*DA's.*/
  61.  
  62. #define    MACINTOSH_ID    40 /*128K, 512K, 512KE, Plus, SE, II*/
  63. #define        SE_ID            41 /*2 diskette, SE HD20*/
  64.  
  65. #define NICE_CAR_ID        100    /*German, Italian, Japanese*/
  66. #define        GERMAN_ID        110 /*Porsche, Mercedes, BMW*/
  67. #define            PORSCHE_ID        111 /*911, 914, 924, 928, 930, 935, 944, 959*/
  68. #define            MERCEDES_ID        112 /*300, 450*/
  69. #define            BMW_ID            113 /*318, 320, 325, 528, 533, 633, 733*/
  70. #define        ITALIAN_ID        120 /*Lamborghini, Ferrari, Lotus*/
  71. #define        JAPANESE_ID        130 /*Honda Prelude, Acura Legend, Mazda RX-7*/
  72.  
  73.  
  74.  
  75. /*Define our global variables.*/
  76.  
  77. MenuHandle        Apple_MH;
  78. MenuHandle        File_MH;
  79. MenuHandle         FontAndDA_MH;
  80. MenuHandle            Font_MH;
  81. MenuHandle            DA_MH;
  82. MenuHandle        Macintosh_MH;
  83. MenuHandle            SE_MH;
  84. MenuHandle        NiceCar_MH;
  85. MenuHandle            German_MH;
  86. MenuHandle                Porsche_MH;
  87. MenuHandle                Mercedes_MH;
  88. MenuHandle                BMW_MH;
  89. MenuHandle            Italian_MH;
  90. MenuHandle            Japanese_MH;
  91.  
  92.  
  93. EventRecord    theEvent;
  94. WindowPtr    theWindow, whichWindow;
  95. int16        windowCode;
  96. int8        theCharacter;
  97.  
  98.  
  99.  
  100. main()
  101. {
  102.     InitGraf(&thePort);
  103.     InitFonts();
  104.     InitWindows();
  105.     InitMenus();
  106.     TEInit();
  107.     InitDialogs(0L);
  108.     InitCursor();
  109.     FlushEvents(everyEvent, 0);
  110.     
  111.     InitializeOurMenus();
  112.     
  113.     
  114.     do {
  115.     
  116.         EventLoop();
  117.         
  118.     } while (TRUE);
  119. }
  120.  
  121.  
  122.  
  123. EventLoop()
  124. {
  125.     /*
  126.     *Give the DA some time.
  127.     */
  128.     
  129.     SystemTask();
  130.     
  131.     /*
  132.     *The event loop.
  133.     *
  134.     *GetNextEvent() will return FALSE if the event is an event that the
  135.     *Desk Manager wants to handle itself (i.e., Desk Accessory events).
  136.     *Refer to I.M. I-258.
  137.     */
  138.         
  139.     if (GetNextEvent(everyEvent, &theEvent) == TRUE) {
  140.         switch(theEvent.what) {
  141.                 
  142.             case keyDown:                       /*Was a key pressed?*/
  143.                 theCharacter = theEvent.message & charCodeMask;
  144.                 if (theEvent.modifiers & cmdKey) { /*Check for a menu*/
  145.                     doMenu(MenuKey(theCharacter)); /*equivalent.*/
  146.                     HiliteMenu(0);
  147.                 }
  148.                 break;
  149.             
  150.             case mouseDown:
  151.                 windowCode = FindWindow(theEvent.where, &whichWindow);
  152.                 switch(windowCode) {
  153.                     
  154.                     case inMenuBar:
  155.                     
  156.                         /*
  157.                         *There was a mouseDown in the menu bar.
  158.                         */
  159.                          
  160.                         doMenu(MenuSelect(theEvent.where));
  161.                         break;
  162.                             
  163.                     case inSysWindow:
  164.                     
  165.                         /*
  166.                         *SystemClick() calls the Desk Manager to handle
  167.                         *mouse_down events which occur in a desk accessory
  168.                         *window (e.g., like in the Control Panel's window).
  169.                         */
  170.                         
  171.                         SystemClick(&theEvent, whichWindow);
  172.                         break;
  173.                 }
  174.                         
  175.             default:
  176.                 break;
  177.             }/*switch(theEvent.what)*/
  178.         }/*if*/
  179. }
  180.  
  181.  
  182.  
  183. InitializeOurMenus()
  184. {
  185.     Apple_MH = NewMenu(APPLE_ID, "\p\024");/*Desk Accessory menu.*/
  186.     AppendMenu(Apple_MH, "\p^1 Software presents…;(-");
  187.     AddResMenu(Apple_MH, 'DRVR');
  188.     InsertMenu(Apple_MH, 0);
  189.  
  190.     File_MH = NewMenu(FILE_ID, "\pFile");  /*File menu.*/
  191.     AppendMenu(File_MH, "\pQuit/Q");
  192.     InsertMenu(File_MH, 0);
  193.     
  194.     
  195.     /*
  196.     *Set up our first hierarchical menu:  Fonts and DAs.
  197.     *
  198.     *Note that we can insert menus even before we define their
  199.     *sub-menus!!!  Octal 033 is hex 1B, which is the <ESC>
  200.     *character.  Octal 024 is the Apple symbol. 
  201.     */
  202.     
  203.     FontAndDA_MH = NewMenu(FONT_N_DA_ID, "\pFonts and DAs");
  204.     AppendMenu(FontAndDA_MH, "\pFonts/\033;\024/\033");
  205.     InsertMenu(FontAndDA_MH, 0);
  206.  
  207.         Font_MH = NewMenu(FONT_ID, "\pFonts (this title is invisible)");
  208.         AddResMenu(Font_MH, 'FONT');
  209.         InsertMenu(Font_MH, -1);
  210.         SetItemMark(FontAndDA_MH, 1, FONT_ID);/*Insert the Font menu beside
  211.                                                *the 1st FontAndDA menu item.
  212.                                                */
  213.  
  214.  
  215.  
  216.         DA_MH = NewMenu(DA_ID, "\p\024 (this title is invisible)");/*Desk Accessory menu.*/
  217.         AddResMenu(DA_MH, 'DRVR');
  218.         InsertMenu(DA_MH, -1);
  219.         SetItemMark(FontAndDA_MH, 2, DA_ID);/*Insert the DA menu beside the
  220.                                              *the 2nd FontAndDA menu item.
  221.                                              */
  222.  
  223.  
  224.  
  225.     /*
  226.     *Set up our second hierarchical menu:  Nice cars.
  227.     *
  228.     *Note that we can insert menus even before we define their
  229.     *sub-menus!!!
  230.     */
  231.     
  232.     NiceCar_MH = NewMenu(NICE_CAR_ID, "\pNice cars");
  233.     AppendMenu(NiceCar_MH, "\pGerman/\033;Italian/\033;Japanese/\033");
  234.     InsertMenu(NiceCar_MH, 0);
  235.  
  236.     
  237.         /*Set up and insert the German sub-menu.*/
  238.         
  239.         German_MH = NewMenu(GERMAN_ID, "\pthis title is invisible");
  240.         AppendMenu(German_MH, "\pPorsche/\033;Mercedes/\033;BMW/\033");
  241.         InsertMenu(German_MH, -1);
  242.         SetItemMark(NiceCar_MH, 1, GERMAN_ID);/*Insert the German menu 
  243.                                                *beside the 1st NiceCars
  244.                                                *menu item.
  245.                                                */
  246.             
  247.             
  248.             /*Set up and insert the Porsche sub-sub-menu.*/
  249.             
  250.             Porsche_MH = NewMenu(PORSCHE_ID, "\pthis title is invisible");
  251.             AppendMenu(Porsche_MH, "\p911;914;924;928;930;935;944;959");
  252.             InsertMenu(Porsche_MH, -1);
  253.             SetItemMark(German_MH, 1, PORSCHE_ID);/*Insert the Porsche menu
  254.                                                    *beside the 1st German
  255.                                                    *menu item.
  256.                                                    */
  257.     
  258.     
  259.             /*Set up and insert the Mercedes sub-sub-menu.*/
  260.             
  261.             Mercedes_MH = NewMenu(MERCEDES_ID, "\pthis title is invisible");
  262.             AppendMenu(Mercedes_MH, "\p300;450");
  263.             InsertMenu(Mercedes_MH, -1);            
  264.             SetItemMark(German_MH, 2, MERCEDES_ID);/*Insert the Mercedes
  265.                                                     *menu beside the 2nd
  266.                                                     *German menu item.
  267.                                                     */
  268.             
  269.             
  270.             /*Set up and insert the BMW sub-sub-menu.*/
  271.             
  272.             BMW_MH = NewMenu(BMW_ID, "\pthis title is invisible");
  273.             AppendMenu(BMW_MH, "\p318;320;325;528;633;733");
  274.             InsertMenu(BMW_MH, -1);            
  275.             SetItemMark(German_MH, 3, BMW_ID);        /*Insert the BMW menu
  276.                                                      *beside the 3rd German
  277.                                                      *menu item.
  278.                                                      */
  279.     
  280.  
  281.         /*Set up and insert the Italian sub-menu.*/
  282.         
  283.         Italian_MH = NewMenu(ITALIAN_ID, "\pthis title is invisible");
  284.         AppendMenu(Italian_MH, "\pLamborghini;Ferrari;Lotus");
  285.         InsertMenu(Italian_MH, -1);        
  286.         SetItemMark(NiceCar_MH, 2, ITALIAN_ID);/*Insert the Italian menu
  287.                                                 *beside the 2nd NiceCar
  288.                                                 *menu item.
  289.                                                 */
  290.         
  291.         
  292.         /*Set up and insert the Japanese sub-menu.*/
  293.         
  294.         Japanese_MH = NewMenu(JAPANESE_ID, "\pthis title is invisible");
  295.         AppendMenu(Japanese_MH, "\pHonda Prelude;Acura Legend;Mazda RX-7");
  296.         InsertMenu(Japanese_MH, -1);        
  297.         SetItemMark(NiceCar_MH, 3, JAPANESE_ID);/*Insert the Japanese menu
  298.                                                  *beside the 3rd NiceCar
  299.                                                  *menu item.
  300.                                                  */
  301.         
  302.         
  303.         
  304.     /*
  305.     *Set up our third hierarchical menu:  Macintoshes.
  306.     *
  307.     *Note that we can insert menus even before we define their
  308.     *sub-menus!!!
  309.     */
  310.     
  311.     Macintosh_MH = NewMenu(MACINTOSH_ID, "\pMacintoshes");
  312.     AppendMenu(Macintosh_MH, "\p128K;512K;512KE;Plus;SE/\033;II");
  313.     InsertMenu(Macintosh_MH, 0);
  314.     
  315.         /*Set up and insert the SE sub-menu.*/
  316.         SE_MH = NewMenu(SE_ID, "\pthis title is invisible");
  317.         AppendMenu(SE_MH, "\pHD 20;2 diskette");
  318.         InsertMenu(SE_MH, -1);    
  319.         SetItemMark(Macintosh_MH, 5, SE_ID);/*Insert the SE menu beside the
  320.                                              *5th Macintosh menu item.
  321.                                              */
  322.  
  323.  
  324.     DrawMenuBar();
  325. }
  326.     
  327.  
  328.  
  329. /*
  330. *This is the subroutine which handles all of the menu commands.
  331. */
  332.  
  333. doMenu(menuResult)
  334. int32 menuResult;
  335. {
  336. GrafPtr theCurrentPort;
  337. Str255 theDAsName, menuItemText;
  338. int16 menuID, itemNumber;
  339.  
  340.     menuID = HiWord(menuResult);
  341.     itemNumber = LoWord(menuResult);
  342.     
  343.     switch(menuID) {
  344.     
  345.         case APPLE_ID:
  346.             if (itemNumber == 1) {
  347.                 ShowAboutWindow();
  348.             }
  349.             else {
  350.             
  351.                 /*
  352.                 *Save the current grafPort, in case the DA doesn't
  353.                 *restore it to the previous value.
  354.                 */
  355.                 
  356.                 GetPort(&theCurrentPort);
  357.                 
  358.                 GetItem(Apple_MH, itemNumber, &theDAsName);
  359.                 OpenDeskAcc(&theDAsName);
  360.                 
  361.                 SetPort(theCurrentPort);
  362.             }
  363.             break;
  364.             
  365.         case FILE_ID:  /*The "File" menu.*/
  366.             switch(itemNumber) {
  367.                 case 1:  
  368.                     ExitToShell();
  369.                     break;
  370.                     
  371.                 default:
  372.                     break;
  373.             }/*switch(itemNumber)*/
  374.             
  375.             break;
  376.         
  377.         /*Handle the sub-menus for the "Font and DAs" hierarchical menu.*/
  378.         case FONT_ID:
  379.             switch(itemNumber) {
  380.                 default:
  381.                     GetItem(Font_MH,  itemNumber, menuItemText); 
  382.                     message("\pYou selected the ", menuItemText, 
  383.                             "\p font.");
  384.                     break;
  385.             }
  386.             break;
  387.             
  388.         case DA_ID:
  389.             switch(itemNumber) {
  390.                 default:
  391.                     GetItem(DA_MH,  itemNumber, menuItemText);
  392.                     message("\pYou selected the \"", menuItemText, 
  393.                             "\p\" DA.");
  394.                         
  395.                     break;
  396.             }
  397.             break;
  398.             
  399.         /*Handle the sub-menus for the "Nice cars" hierarchical menu.*/
  400.         case PORSCHE_ID:
  401.             switch(itemNumber) {
  402.                 default:
  403.                     GetItem(Porsche_MH,  itemNumber, menuItemText);
  404.                     message("\pYou selected the ",
  405.                              menuItemText, 
  406.                              "\p Porsche.");
  407.                     break;
  408.             }
  409.             break;
  410.             
  411.         case MERCEDES_ID:
  412.             switch(itemNumber) {
  413.                 default: 
  414.                     GetItem(Mercedes_MH,  itemNumber, menuItemText);
  415.                     message("\pYou selected the ",
  416.                              menuItemText, 
  417.                              "\p Mercedes.");
  418.                     break;
  419.             }
  420.             break;
  421.             
  422.         case BMW_ID:
  423.             switch(itemNumber) {
  424.                 default:
  425.                     GetItem(BMW_MH,  itemNumber, menuItemText);
  426.                     message("\pYou selected the ",
  427.                              menuItemText, 
  428.                              "\p BMW.");
  429.                     break;
  430.             }
  431.             break;
  432.             
  433.         case ITALIAN_ID:
  434.             switch(itemNumber) {
  435.                 default:
  436.                     GetItem(Italian_MH, itemNumber, menuItemText);
  437.                     message("\pYou selected the ",
  438.                             menuItemText, "\p.");
  439.                     break;
  440.             }
  441.             break;
  442.             
  443.         case JAPANESE_ID:
  444.             switch(itemNumber) {
  445.                 default:
  446.                     GetItem(Japanese_MH, itemNumber, menuItemText);
  447.                     message("\pYou selected the ",
  448.                             menuItemText, "\p.");
  449.                     break;
  450.             }
  451.             break;
  452.             
  453.         /*Handle the Macintosh menu, and sub-menu.*/
  454.         case MACINTOSH_ID:
  455.             switch(itemNumber) {
  456.                 default:
  457.                     GetItem(Macintosh_MH, itemNumber, menuItemText);
  458.                     message("\pYou selected the Mac ",
  459.                             menuItemText, "\p.");
  460.                     break;
  461.             }
  462.             break;
  463.     
  464.         case SE_ID:
  465.             switch(itemNumber) {
  466.                 default:
  467.                     GetItem(SE_MH, itemNumber, menuItemText);
  468.                     message("\pYou selected the Mac SE ",
  469.                             menuItemText, "\p.");
  470.                     break;
  471.             }
  472.             break;
  473.         
  474.         default:
  475.             break;
  476.         }/*switch(menuID)*/
  477.     
  478.     HiliteMenu(0);/*Don't forget to un-hilite the menu bar after 
  479.                     you're done performing that menu item command.*/
  480. }
  481.         
  482.         
  483.         
  484. /*
  485. *ShowAboutWindow() puts up a window when the user selects the "About DA…" 
  486. *command from the apple menu.  To exit this window and return to the 
  487. *program, the user has to click the mouse button.        
  488. */
  489.  
  490. ShowAboutWindow()
  491. {
  492. EventRecord    theEvent;
  493. GrafPtr     DA_AboutBox_Port;
  494. WindowPtr    AboutWindow;
  495. Rect        AboutRect, RectForOneLineOfText;
  496. int8        *line1, *line2, *line3, *line4, *line5;
  497.  
  498.     line1 = "Hier Menu Demo,";
  499.     line2 = "a tutorial program";
  500.     line3 = "by Ted C. Johnson";
  501.     line4 = "President of T Bear Software™";
  502.     line5 = "Copyright © 1988 by Ted C. Johnson";
  503.     
  504.     GetPort(&DA_AboutBox_Port); /*Preserve the DA_About_Box port.*/
  505.     
  506.     SetRect(&AboutRect, 75, 110, 425, 230);/*Window size and position.*/
  507.     
  508.     SetRect(&RectForOneLineOfText, 5, 10, 345, 25);/*Box for first line of text.*/
  509.     
  510.     AboutWindow = NewWindow((WindowPeek)NIL, &AboutRect, "\p", TRUE,
  511.                             altDBoxProc, (WindowPtr)-1, TRUE, 0);
  512.     SetPort(AboutWindow);
  513.     
  514.     /*
  515.     *Choose the system font (Chicago), 12 point size.
  516.     */
  517.     
  518.     TextSize(12);
  519.  
  520.  
  521.     TextFont(systemFont);
  522.     
  523.     /*
  524.     *Draw the text.  Offset the RectForOneLineOfText box 20 pixels down and
  525.     *and 0 pixels the right, for each line of text.  Use different styles 
  526.     *of text for each line, just for the heck of it.  See I.M, page I-171.                
  527.     */
  528.     
  529.     TextFace(shadow);
  530.     TextBox(line1, strlen(line1), &RectForOneLineOfText, teJustCenter);
  531.     
  532.     OffsetRect(&RectForOneLineOfText, 0, 20);
  533.     TextFace(underline);
  534.     TextBox(line2, strlen(line2), &RectForOneLineOfText, teJustCenter);
  535.     
  536.     OffsetRect(&RectForOneLineOfText, 0, 20);
  537.     TextFace(italic);
  538.     TextBox(line3, strlen(line3), &RectForOneLineOfText, teJustCenter);
  539.         
  540.     OffsetRect(&RectForOneLineOfText, 0, 20);
  541.     TextFace(bold);
  542.     TextBox(line4, strlen(line4), &RectForOneLineOfText, teJustCenter);
  543.         
  544.     OffsetRect(&RectForOneLineOfText, 0, 20);
  545.     TextFace(0);
  546.     TextBox(line5, strlen(line5), &RectForOneLineOfText, teJustCenter);
  547.     
  548.     /*
  549.     *Wait for a mouse-down event.  When you get one, erase the About
  550.     *Window, and return to DA_AboutBox Demo window.  
  551.     */
  552.     
  553.     do {
  554.     
  555.         GetNextEvent(everyEvent, &theEvent); 
  556.         
  557.     } while (theEvent.what != mouseDown);
  558.     
  559.     /*
  560.     *DisposeWindow() calls CloseWindow(), then releases the memory
  561.     *occupied by the window record.
  562.     */
  563.     
  564.     DisposeWindow(AboutWindow);
  565.     
  566.     SetPort(DA_AboutBox_Port);
  567. }
  568.  
  569.  
  570.  
  571. /*
  572. *showDialog() puts up a modal dialog box and returns the
  573. *number corresponding to the button pushed.        
  574. */
  575.  
  576. int16 showDialog(dialogNumber, maxbutton)
  577. int16 dialogNumber;
  578. int16 maxbutton;
  579. {
  580. DialogPtr dialog;            /* pointer to the dialog */
  581. DialogRecord dialogRecord;    /* actual dialog record */
  582. int16 itemHit = maxbutton + 1;
  583.  
  584.     /* bring up the dialog box */
  585.     dialog = GetNewDialog(dialogNumber, &dialogRecord, (WindowPtr) -1);
  586.     ShowWindow(dialog);
  587.  
  588.     while (itemHit > maxbutton)
  589.     {
  590.         ModalDialog((ProcPtr) NIL, &itemHit);
  591.     }
  592.     
  593.     CloseDialog(dialog); 
  594.     
  595.     return(itemHit);
  596. }
  597.  
  598.  
  599.  
  600. message(string1, string2, string3)
  601. int8 *string1, *string2, *string3;        /* expect pascal string */
  602. {
  603.     ParamText(string1, string2, string3, "\p");
  604.     showDialog(DIALOG_MESSAGE, 1);
  605. }
  606.  
  607.  
  608.  
  609. messageWithInt(string, theInt)
  610. int8 *string;        /* expect pascal string */
  611. int16 theInt;
  612. {
  613. Str255 tempString;
  614.     
  615.     NumToString(theInt, &tempString);
  616.     ParamText(string, tempString, "\p", "\p");
  617.     showDialog(DIALOG_MESSAGE, 1);
  618. }
  619.  
  620.  
  621. strlen(s)
  622. register int8 *s;
  623. {
  624. int8 *s0 = s;
  625.  
  626.     while(*s++);
  627.     return(s - s0 -1);
  628. }